package bsh;

import org.objectweb.asm.MethodVisitor;

import bsh.exception.CompilationAssertionFailed;
import bsh.exception.CompilationFailedException;
import bsh.meta.Scope;
import bsh.meta.TypeWrapper;

/**
 * @author takeshi
 */
public class PrimaryExpressionCompiler implements NodeCompiler {

    private final BSHPrimaryExpression node;

    private final CompilationUnit unit;

    /**
     * @param node node
     * @param unit unit
     */
    public PrimaryExpressionCompiler(BSHPrimaryExpression node, CompilationUnit unit) {
        super();
        this.node = node;
        this.unit = unit;
    }

    /**
     * {@inheritDoc}
     * 
     * @see bsh.NodeCompiler#compile(org.objectweb.asm.MethodVisitor, bsh.CompilationState)
     */
    public void compile(MethodVisitor host, CompilationState state) throws CompilationFailedException {
        state.addLineNumber(host, this.node.getLineNumber());
        int numChildren = this.node.jjtGetNumChildren();
        for (int i = 0; i < numChildren; i++) {
            SimpleNode child = this.node.getChild(i);
            this.unit.getNodeCompiler(child).compile(host, state);
        }
    }

    /**
     * {@inheritDoc}
     * 
     * @see bsh.NodeCompiler#nodeResultType(bsh.meta.Scope)
     */
    public TypeWrapper nodeResultType(Scope scope) throws CompilationFailedException {
        int numChildren = this.node.jjtGetNumChildren();
        if (numChildren == 0) {
            throw new CompilationAssertionFailed("cannot have a primary expression with no children");
        }
        TypeWrapper nodeType = this.unit.getNodeType(this.node.getChild(0), scope);
        for (int i = 0; i < numChildren; i++) {
            SimpleNode other = this.node.getChild(i);
            if (other instanceof BSHPrimarySuffix) {
                // special treatment
                PrimarySuffixCompiler nodeCompiler = (PrimarySuffixCompiler) this.unit.getNodeCompiler(other);
                nodeType = nodeCompiler.nodeResultTypeFrom(nodeType, scope);
            } else {
                nodeType = this.unit.getNodeType(other, scope);
            }
        }
        return nodeType;
    }

}
